package com.after.saas.file.config;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

import java.lang.reflect.Method;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Description
 * @Classname TaskPoolConfig
 * @Author hjchen
 * @Version V1.0.0
 * @Since 1.0
 * @Date 2022/12/26 10:11
 */

@Data
@Slf4j
@EnableAsync
@Configuration
@EnableScheduling
@ConfigurationProperties("task.thread-pool")
public class TaskPoolConfig implements AsyncConfigurer {

    private int keepAliveTime;
    private int coreSize;
    private int maxSize;
    private int queueSize;

    @Bean
    @Override
    @Primary
    public ThreadPoolTaskExecutor getAsyncExecutor() {
        initCoreSize();
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(coreSize);
        // 设置最大线程数
        executor.setMaxPoolSize(maxSize);
        // 设置队列容量
        executor.setQueueCapacity(queueSize);
        // 设置线程活跃时间（秒）
        executor.setKeepAliveSeconds(keepAliveTime);
        // 设置默认线程名称
        executor.setThreadNamePrefix("customer-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 该方法用来设置 线程池关闭 的时候 等待 所有任务都完成后，再继续 销毁 其他的 Bean，
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 任务的等待时间 如果超过这个时间还没有销毁就 强制销毁，以确保应用最后能够被关闭，而不是阻塞住。
        executor.setAwaitTerminationSeconds(60);
        return executor;
    }

    @Bean(name = "threadPoolTaskScheduler")
    public ThreadPoolTaskScheduler taskScheduler() {
        // Spring 默认配置是核心线程数大小为1，最大线程容量大小不受限制，队列容量也不受限制。
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        // 核心线程数
        scheduler.setPoolSize(1);
        scheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        scheduler.setThreadNamePrefix("cron-");
        //表明是否等待所有线程执行完任务
        scheduler.setWaitForTasksToCompleteOnShutdown(true);
        //等待的时间，超过这个时间就强制销毁，因为不能无限的等待下去以确保应用最后能够被关闭
        scheduler.setAwaitTerminationSeconds(60);
        return scheduler;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SpringAsyncExceptionHandler();
    }

    static class SpringAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
        @Override
        public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
            log.error("method {},args{},error:{}", method.getName(), objects, throwable.getMessage());
        }
    }

    private void initCoreSize() {
        int core = Runtime.getRuntime().availableProcessors() * 2;
        if (coreSize < core) {
            coreSize = core;
            maxSize = core + 1;
        }
        log.info("coreSize:{},maxSize:{}", coreSize, maxSize);
    }
}
